package com.zhidao.backend.service.Impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.zhidao.backend.common.PublishRequest;
import com.zhidao.backend.common.StatusCode;
import com.zhidao.backend.entity.Route;
import com.zhidao.backend.exception.BusinessException;
import com.zhidao.backend.mapper.RouteMapper;
import com.zhidao.backend.service.IRouteService;
import com.zhidao.backend.util.AlgorithmUtil;
import javafx.util.Pair;
import org.springframework.stereotype.Service;

import java.sql.Timestamp;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 路线服务实现
 */
@Service
public class RouteServiceImpl extends ServiceImpl<RouteMapper, Route> implements IRouteService {
    @Override
    public List<Route> search(String keyword) {
        QueryWrapper<Route> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("status", 3);
        List<Route> routeList = baseMapper.selectList(queryWrapper);
        Gson gson = new Gson();
        //按点赞数排序
        return routeList.stream().filter(route -> {
            String tagStr = route.getTagStr();
            Set<String> tags = gson.fromJson(tagStr, new TypeToken<Set<String>>(){}.getType());
            return route.getTitle().contains(keyword) || route.getDescription().contains(keyword) || tags.contains(keyword);
        }).sorted(Comparator.comparingInt(Route::getLikes).reversed()).collect(Collectors.toList());
    }

    @Override
    public List<Route> getRoutes(Long id) {
        return baseMapper.selectList(new QueryWrapper<Route>().eq("author", id).eq("status", 3));
    }

    @Override
    public List<Route> getDrafts(Long id) {
        return baseMapper.selectList(new QueryWrapper<Route>().eq("author", id).eq("status", 1));
    }

    @Override
    public List<Route> getAuditingRoutes(Long id) {
        return baseMapper.selectList(new QueryWrapper<Route>().eq("author", id).eq("status", 2));
    }

    @Override
    public List<Route> getReturnRoutes(Long id) {
        return baseMapper.selectList(new QueryWrapper<Route>().eq("author", id).eq("status", 4));
    }


    @Override
    public void likeRoute(Long id) {
        Route route = baseMapper.selectById(id);
        route.setLikes(route.getLikes() + 1);
        int res = baseMapper.updateById(route);
        if (res < 1) {
            throw new BusinessException(StatusCode.SYSTEM_ERROR.getCode(), "点赞失败，请重试");
        }
    }

    @Override
    public void collectRoute(Long id) {
        Route route = baseMapper.selectById(id);
        route.setCollects(route.getCollects() + 1);
        int res = baseMapper.updateById(route);
        if (res < 1) {
            throw new BusinessException(StatusCode.SYSTEM_ERROR.getCode(), "收藏失败，请重试");
        }
    }

    @Override
    public Long publishRoute(PublishRequest publishRequest) {
        Route route = new Route();
        route.setTitle(publishRequest.getRoute().getTitle());
        route.setDescription(publishRequest.getRoute().getDescription());
        if (publishRequest.getRoute().getCover().equals("")) {
            route.setCover("https://zhidaobackend.oss-cn-hangzhou.aliyuncs.com/zhidao/images/2022/11/11/b2bfabb0-7c29-4337-9675-cf154af74205.jpg");
        } else {
            route.setCover(publishRequest.getRoute().getCover());
        }
        route.setViews(0);
        route.setLikes(0);
        route.setCollects(0);
        route.setAuthor(publishRequest.getRoute().getAuthor());
        Date date = new Date();
        Timestamp timestamp = new Timestamp(date.getTime());
        route.setPostTime(timestamp);
        route.setTags(publishRequest.getRoute().getTags());
        Gson gson = new Gson();
        route.setTagStr(gson.toJson(route.getTags()));
        if (publishRequest.getIsDraft()) {
            route.setStatus(1);
        } else {
            route.setStatus(2);
        }
        route.setRecommend(false);
        route.setDeleted(false);
        int res = baseMapper.insert(route);
        if (res < 1) {
            throw new BusinessException(StatusCode.SYSTEM_ERROR.getCode(), "发布失败，请重试");
        }
        return route.getId();
    }

    @Override
    public void cancelCollectRoute(Long id) {
        Route route = baseMapper.selectById(id);
        route.setCollects(route.getCollects() - 1);
        int res = baseMapper.updateById(route);
        if (res < 1) {
            throw new BusinessException(StatusCode.SYSTEM_ERROR.getCode(), "取消收藏失败，请重试");
        }
    }

    @Override
    public void unlikeRoute(Long routeId) {
        Route route = baseMapper.selectById(routeId);
        route.setLikes(route.getLikes() - 1);
        int res = baseMapper.updateById(route);
        if (res < 1) {
            throw new BusinessException(StatusCode.SYSTEM_ERROR.getCode(), "取消点赞失败，请重试");
        }
    }

    @Override
    public void learnRoute(Long routeId) {
        Route route = baseMapper.selectById(routeId);
        route.setViews(route.getViews() + 1);
        int res = baseMapper.updateById(route);
        if (res < 1) {
            throw new BusinessException(StatusCode.SYSTEM_ERROR.getCode(), "学习失败，请重试");
        }
    }

    @Override
    public void cancelLearnRoute(Long routeId) {
        Route route = baseMapper.selectById(routeId);
        route.setViews(route.getViews() - 1);
        int res = baseMapper.updateById(route);
        if (res < 1) {
            throw new BusinessException(StatusCode.SYSTEM_ERROR.getCode(), "取消学习失败，请重试");
        }
    }

    @Override
    public List<Route> randomRoutes() {
        List<Route> routeList = baseMapper.selectList(new QueryWrapper<Route>().eq("status", 3));
        List<Route> finalRouteList = new ArrayList<>();
        int[] randomIndex = AlgorithmUtil.randomArray(0, routeList.size() - 1);
        for (int i = 0; i < 8; i++) {
            finalRouteList.add(routeList.get(randomIndex[i]));
        }
        return finalRouteList.stream().peek(route -> route.setTags(new Gson().fromJson(route.getTagStr(), new TypeToken<List<String>>(){}.getType())))
                .sorted(Comparator.comparing(Route::getViews).reversed()).collect(Collectors.toList());
    }

    @Override
    public List<Route> personalizedRoutes(String tagStr) {
        Gson gson = new Gson();
        List<String> userTags = gson.fromJson(tagStr, new TypeToken<List<String>>(){}.getType());
        QueryWrapper<Route> queryWrapper = new QueryWrapper<>();
        //queryWrapper.select("id","tags");
        queryWrapper.eq("status", 3);
        queryWrapper.isNotNull("tags");
        List<Route> routeList = baseMapper.selectList(queryWrapper);
        //System.out.println(routeList);
        List<Pair<Route, Integer>> pairList = new ArrayList<>();
        for (Route route : routeList) {
            List<String> tags = gson.fromJson(route.getTagStr(), new TypeToken<List<String>>(){}.getType());
            int distance = AlgorithmUtil.editDistance(userTags, tags);
            pairList.add(new Pair<>(route, distance));
        }
        List<Pair<Route, Integer>> topMatchRouteList = pairList.stream().sorted(Comparator.comparingInt(Pair::getValue)).collect(Collectors.toList());
        List<Route> topRouteList = topMatchRouteList.stream().map(Pair::getKey).peek(route ->
            route.setTags(new Gson().fromJson(route.getTagStr(), new TypeToken<List<String>>(){}.getType()))
        ).limit(20).collect(Collectors.toList());
        int[] randomIndex = AlgorithmUtil.randomArray(0, topRouteList.size() - 1);
        List<Route> finalRouteList = new ArrayList<>();
        for (int i = 0; i < 8; i++) {
            finalRouteList.add(topRouteList.get(randomIndex[i]));
        }
        return finalRouteList.stream().sorted(Comparator.comparingInt(Route::getViews).reversed()).collect(Collectors.toList());
    }

    @Override
    public List<Route> getRoutesById(List<Long> routesId) {
        //确保顺序
        return baseMapper.selectBatchIds(routesId);
    }

    @Override
    public void deleteById(Route route){baseMapper.deleteById(route);}
    @Override
    public List<Route> getCheckPendingRoutes(){
        QueryWrapper<Route> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("status",2);
        queryWrapper.orderByDesc("post_time");
        return baseMapper.selectList(queryWrapper).stream().peek(route -> route.setTags(new Gson().fromJson(route.getTagStr(), new TypeToken<List<String>>(){}.getType()))).collect(Collectors.toList());
    }

    @Override
    public List<Route> getCheckPassedRoutes() {
        QueryWrapper<Route> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("status",3);
        queryWrapper.orderByDesc("id");
        return baseMapper.selectList(queryWrapper).stream().peek(route -> route.setTags(new Gson().fromJson(route.getTagStr(), new TypeToken<List<String>>(){}.getType()))).collect(Collectors.toList());
    }

    @Override
    public List<Route> carouselRoutes() {
        QueryWrapper<Route> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("status",3);
        queryWrapper.eq("recommend",1);
        //按时间从新到旧排序
        queryWrapper.orderByDesc("id");
        return baseMapper.selectList(queryWrapper).stream().peek(route -> route.setTags(new Gson().fromJson(route.getTagStr(), new TypeToken<List<String>>(){}.getType()))).limit(3).collect(Collectors.toList());
    }
}
